#!/bin/sh /etc/rc.common
# Copyright (C) 2019 - 2021 Ycarus (Yannick Chabanois) <ycarus@zugaina.org> for OpenMPTCProuter
# Released under GPL 3. See LICENSE for the full terms.

{
	START=99
	STOP=10
	USE_PROCD=1
}

wireguard_restart() {
	local interface=$1
	if [ "$(uci -q get network.${interface}.proto)" = "wireguard" ] && [ -n "$(uci -q get network.${interface}.fwmark)" ]; then
		ifdown ${interface}
		ifup ${interface}
	fi
}

_getremoteip() {
	[ "$(uci -q get openmptcprouter.$1.current)" = "1" ] && {
		remoteip=$(uci -q get openmptcprouter.$1.ip | awk '{print $1}')
		wg_server_key=$(uci -q get openmptcprouter.$1.wgkey)
	}
}

mptcp_over_vpn() {
	local interface=$1
	[ -n "$(uci show firewall.zone_wan.network | grep $interface)" ] && nbintf=$(($nbintf+1))
	if [ "$(uci -q get openmptcprouter.${interface}.multipathvpn)" = "1" ]; then
		remoteip=""
		config_load openmptcprouter
		config_foreach _getremoteip server

		if [ "$(uci -q get network.${interface})" = "" ]; then
			uci -q batch <<-EOF >/dev/null
				delete openmptcprouter.${interface}
				delete network.ovpn${interface}
				delete network.wg${interface}
				delete network.@wireguard_wg${interface}[0]
				delete openvpn.${interface}
				commit openvpn
				delete openmptcprouter.${interface}
				delete openmptcprouter.ovpn${interface}
				delete openmptcprouter.wg${interface}
				commit openmptcprouter
				commit network
				del_list firewall.zone_vpn.network="ovpn${interface}"
				del_list firewall.zone_vpn.network="wg${interface}"
				commit firewall
			EOF
			return
		fi
		nbintfvpn=$(($nbintfvpn+1))
		if ([ "$(uci -q get network.ovpn${interface})" = "" ] || [ "$(uci -q get openvpn.${interface}.remote)" != "${remoteip}" ]) && [ "$vpn" = "openvpn" ]; then
			logger -t "MPTCPoverVPN" "Enable MPTCP over VPN for ${interface}"
			id=$(uci -q get network.${interface}.metric)
			localip=$(ubus call network.interface.$interface status | jsonfilter -e '@["ipv4-address"][0].address' | tr -d "\n")
			[ -z "$(uci -q get openmptcprouter.ovpn${interface}.multipath)" ] && multipath=$(uci -q get network.${interface}.multipath)
			[ -n "$(uci -q get openmptcprouter.ovpn${interface}.multipath)" ] && multipath=$(uci -q get openmptcprouter.ovpn${interface}.multipath)
			[ -z "$multipath" ] && multipath="on"
			uci -q batch <<-EOF >/dev/null
				delete network.wg${interface}
				delete openmptcprouter.wg${interface}
				commit openmptcprouter
				commit network
				del_list firewall.zone_vpn.network="wg${interface}"
				commit firewall
			EOF

				uci -q batch <<-EOF >/dev/null
					set network.ovpn${interface}=interface
					set network.ovpn${interface}.device="tun${id}"
					set network.ovpn${interface}.defaultroute='0'
					set network.ovpn${interface}.peerdns='0'
					set network.ovpn${interface}.proto='none'
					set network.ovpn${interface}.ip4table='wan'
					set network.ovpn${interface}.multipath="${multipath}"
					set network.${interface}.multipath='off'
					commit network
					set openvpn.${interface}=openvpn
					set openvpn.${interface}.dev="tun${id}"
					set openvpn.${interface}.cipher='AES-256-CBC'
					set openvpn.${interface}.port='65301'
					set openvpn.${interface}.remote="${remoteip}"
					set openvpn.${interface}.local="${localip}"
					set openvpn.${interface}.lport='0'
					set openvpn.${interface}.ncp_disable='1'
					set openvpn.${interface}.auth_nocache='1'
					set openvpn.${interface}.proto='udp'
					set openvpn.${interface}.client='1'
					set openvpn.${interface}.enabled='1'
					set openvpn.${interface}.allow_recursive_routing='1'
					set openvpn.${interface}.key='/etc/luci-uploads/client.key'
					set openvpn.${interface}.cert='/etc/luci-uploads/client.crt'
					set openvpn.${interface}.ca='/etc/luci-uploads/ca.crt'
					commit openvpn
					set openmptcprouter.${interface}.multipath="off"
					set openmptcprouter.${interface}.multipathvpn="1"
					set openmptcprouter.ovpn${interface}="interface"
					set openmptcprouter.ovpn${interface}.multipath="${multipath}"
					set openmptcprouter.ovpn${interface}.vpn="1"
					set openmptcprouter.ovpn${interface}.baseintf="${interface}"
					commit openmptcprouter
					add_list firewall.zone_vpn.network="ovpn${interface}"
					commit firewall
				EOF
		elif ([ "$(uci -q get network.wg${interface})" = "" ] || [ "$(uci -q get network.@wireguard_wg${interface}[0].endpoint_host)" != "$remoteip" ]) && [ "$vpn" = "wireguard" ]; then
			logger -t "MPTCPoverVPN" "Enable MPTCP over VPN for ${interface}"
			id=$(uci -q get network.${interface}.metric)
			remoteip=""
			wg_server_key=""
			config_load openmptcprouter
			config_foreach _getremoteip server
			metric=$(uci -q get network.${interface}.metric)
			[ -z "$(uci -q get openmptcprouter.wg${interface}.multipath)" ] && multipath=$(uci -q get network.${interface}.multipath)
			[ -n "$(uci -q get openmptcprouter.wg${interface}.multipath)" ] && multipath=$(uci -q get openmptcprouter.wg${interface}.multipath)
			[ -z "$multipath" ] && multipath="on"
				private_key=$(wg genkey | tr -d "\n")
				public_key=$(echo $private_key | wg pubkey | tr -d "\n")
			uci -q batch <<-EOF >/dev/null
				delete network.ovpn${interface}
				delete openvpn.${interface}
				commit openvpn
				delete openmptcprouter.ovpn${interface}
				commit openmptcprouter
				commit network
				del_list firewall.zone_vpn.network="ovpn${interface}"
				commit firewall
			EOF

				uci -q batch <<-EOF >/dev/null
					set network.wg${interface}=interface
					set network.wg${interface}.nohostroute='1'
					set network.wg${interface}.proto='wireguard'
					set network.wg${interface}.fwmark="0x539${metric}"
					del_list network.wg${interface}.addresses
					add_list network.wg${interface}.addresses='10.255.247.${metric}/24'
					set network.wg${interface}.private_key="${private_key}"
					set network.wg${interface}.gateway="10.255.247.1"
					set network.wg${interface}.public_key="${public_key}"
					set network.wg${interface}.multipath="${multipath}"
					set network.${interface}.multipath='off'
					add network wireguard_wg${interface}
					set network.@wireguard_wg${interface}[0]=wireguard_wg${interface}
					set network.@wireguard_wg${interface}[0].description="Wireguard on ${interface}"
					set network.@wireguard_wg${interface}[0].endpoint_host="${remoteip}"
					set network.@wireguard_wg${interface}[0].endpoint_port="65311"
					set network.@wireguard_wg${interface}[0].persistent_keepalive="28"
					del_list network.@wireguard_wg${interface}[0].allowed_ips
					add_list network.@wireguard_wg${interface}[0].allowed_ips="0.0.0.0/0"
					set network.@wireguard_wg${interface}[0].public_key="${wg_server_key}"
					commit network
					set openmptcprouter.${interface}.multipath="off"
					set openmptcprouter.${interface}.multipathvpn="1"
					set openmptcprouter.wg${interface}="interface"
					set openmptcprouter.wg${interface}.multipath="${multipath}"
					set openmptcprouter.wg${interface}.vpn="1"
					set openmptcprouter.wg${interface}.baseintf="${interface}"
					commit openmptcprouter
					add_list firewall.zone_vpn.network="wg${interface}"
					commit firewall
				EOF
			ubus call network reload 2>&1 >/dev/null
		else
			uci -q batch <<-EOF >/dev/null
				set network.${interface}.multipath='off'
				commit network
				set openmptcprouter.${interface}.multipath="off"
				commit openmptcprouter
			EOF
		fi
	elif [ "$(uci -q get openmptcprouter.ovpn${interface})" != "" ] || [ "$(uci -q get network.wg${interface})" != "" ]; then
		logger -t "MPTCPoverVPN" "Disable MPTCP over VPN for ${interface}"
		multipath=$(uci -q get openmptcprouter.ovpn${interface}.multipath)
		[ -z "$multipath" ] && multipath="on"
		uci -q batch <<-EOF >/dev/null
			delete network.wg${interface}
			delete network.@wireguard_wg${interface}[0]
			delete network.ovpn${interface}
			delete openvpn.${interface}
			commit openvpn
			set openmptcprouter.${interface}.multipath="${multipath}"
			set network.${interface}.multipath="${multipath}"
			set openmptcprouter.${interface}.multipathvpn="0"
			delete openmptcprouter.ovpn${interface}
			delete openmptcprouter.wg${interface}
			commit openmptcprouter
			commit network
			del_list firewall.zone_vpn.network="ovpn${interface}"
			del_list firewall.zone_vpn.network="wg${interface}"
			commit firewall
		EOF
	elif [ "$(uci -q get openmptcprouter.${interface}.vpn)" = "1" ]; then
		intf="$(echo ${interface} | sed 's/ovpn//g')"
		[ "$intf" = "$interface" ] && intf="$(echo ${interface} | sed 's/wg//g')"
		if [ -n "$intf" ] && [ "$intf" != "$interface" ] && [ "$(uci -q get network.${intf})" = "" ]; then
			uci -q batch <<-EOF >/dev/null
				delete network.${interface}
				delete network.@wireguard_${interface}[0]
				delete openvpn.ovpn${intf}
				commit openvpn
				delete openmptcprouter.${intf}
				delete openmptcprouter.ovpn${intf}
				delete openmptcprouter.${interface}
				commit openmptcprouter
				commit network
				del_list firewall.zone_vpn.network="${interface}"
				commit firewall
			EOF
		fi
	fi
}

start_service()
{
	nbintf=0
	nbintfvpn=0
	vpn="$(uci -q get openmptcprouter.settings.mptcpovervpn)"
	[ -z "$vpn" ] && vpn="openvpn"
	config_load openmptcprouter
	config_foreach mptcp_over_vpn interface
	if [ "$nbintf" = "$nbintfvpn" ] &&  [ "$nbintf" != "0" ] && [ "$nbintfvpn" != "0" ]; then
		uci -q batch <<-EOF >/dev/null
			set openmptcprouter.settings.allmptcpovervpn='1'
			commit openmptcprouter
		EOF
	else
		uci -q batch <<-EOF >/dev/null
			set openmptcprouter.settings.allmptcpovervpn='0'
			commit openmptcprouter
		EOF
	fi
	if [ "$nbintf" = "$nbintfvpn" ] &&  [ "$nbintf" != "0" ]; then
		if [ "$vpn" = "openvpn" ]; then
			uci -q batch <<-EOF >/dev/null
				set shadowsocks-libev.sss0.disabled='1'
				set glorytun.vpn.host='10.255.250.1'
				set glorytun-udp.vpn.host='10.255.250.1'
				commit glorytun
				commit glorytun-udp
			EOF
		else
			uci -q batch <<-EOF >/dev/null
				set shadowsocks-libev.sss0.disabled='1'
				set glorytun.vpn.host='10.255.247.1'
				set glorytun-udp.vpn.host='10.255.247.1'
				commit glorytun
				commit glorytun-udp
			EOF
		fi
		uci -q batch <<-EOF >/dev/null
			set shadowsocks-libev.ss_rules.server='mptcpovervpn'
			set shadowsocks-libev.ss_rules.redir_tcp='all'
		EOF
	elif ([ "$(uci -q get glorytun.vpn.host)" = "10.255.250.1" ] || [ "$(uci -q get glorytun.vpn.host)" = "10.255.247.1" ] || [ "$(uci -q get shadowsocks-libev.ss_rules.server)" != "sss0" ]) && [ "$nbintf" != "$nbintfvpn" ]; then
		uci -q batch <<-EOF >/dev/null
			set shadowsocks-libev.sss0.disabled='0'
			set shadowsocks-libev.ss_rules.server='sss0'
			set glorytun.vpn.host="$(uci -q get openmptcprouter.vps.ip | awk '{print $1}')"
			set glorytun-udp.vpn.host="$(uci -q get openmptcprouter.vps.ip | awk '{print $1}')"
			commit glorytun
			commit glorytun-udp
		EOF
	fi
	NBCPU=$(grep -c '^processor' /proc/cpuinfo | tr -d "\n")
	if [ "$nbintfvpn" != 0 ]; then
		if [ "$vpn" = "openvpn" ]; then
			uci -q batch <<-EOF >/dev/null
				set shadowsocks-libev.mptcpovervpn=server
				set shadowsocks-libev.mptcpovervpn.server_port="$(uci -q get shadowsocks-libev.sss0.server_port)"
				set shadowsocks-libev.mptcpovervpn.key="$(uci -q get shadowsocks-libev.sss0.key)"
				set shadowsocks-libev.mptcpovervpn.method="$(uci -q get shadowsocks-libev.sss0.method)"
				set shadowsocks-libev.mptcpovervpn.server="10.255.250.1"
				set shadowsocks-libev.mptcpovervpn.disabled='0'
			EOF
		else
			uci -q batch <<-EOF >/dev/null
				set shadowsocks-libev.mptcpovervpn=server
				set shadowsocks-libev.mptcpovervpn.server_port="$(uci -q get shadowsocks-libev.sss0.server_port)"
				set shadowsocks-libev.mptcpovervpn.key="$(uci -q get shadowsocks-libev.sss0.key)"
				set shadowsocks-libev.mptcpovervpn.method="$(uci -q get shadowsocks-libev.sss0.method)"
				set shadowsocks-libev.mptcpovervpn.server="10.255.247.1"
				set shadowsocks-libev.mptcpovervpn.disabled='0'
			EOF
		fi
		for c in $(seq 1 $NBCPU); do
			uci -q batch <<-EOF >/dev/null
				set shadowsocks-libev.hivpn$c=ss_redir
				set shadowsocks-libev.hivpn$c.server="mptcpovervpn"
				set shadowsocks-libev.hivpn$c.local_address='0.0.0.0'
				set shadowsocks-libev.hivpn$c.local_port='1101'
				set shadowsocks-libev.hivpn$c.mode='tcp_and_udp'
				set shadowsocks-libev.hivpn$c.timeout='1000'
				set shadowsocks-libev.hivpn$c.fast_open='1'
				set shadowsocks-libev.hivpn$c.verbose='0'
				set shadowsocks-libev.hivpn$c.syslog='1'
				set shadowsocks-libev.hivpn$c.reuse_port='1'
				set shadowsocks-libev.hivpn$c.mptcp='1'
				set shadowsocks-libev.hivpn$c.ipv6_first='1'
				set shadowsocks-libev.hivpn$c.no_delay='1'
			EOF
		done
		uci -q batch <<-EOF >/dev/null
			commit shadowsocks-libev
		EOF
		/etc/init.d/shadowsocks-libev restart
		/etc/init.d/openvpn restart
	elif [ "$(uci -q get shadowsocks-libev.hivpn1)" != "" ]; then
		for c in $(seq 1 $NBCPU); do
			uci -q batch <<-EOF >/dev/null
				delete shadowsocks-libev.hivpn$c
			EOF
		done
		uci -q batch <<-EOF >/dev/null
			set shadowsocks-libev.sss0.disabled='0'
		EOF
		uci -q batch <<-EOF >/dev/null
			set shadowsocks-libev.ss_rules.server='sss0'
			delete shadowsocks-libev.mptcpovervpn
			commit shadowsocks-libev
		EOF
	fi
	if [ "$BOOT" = "1" ]; then
		config_load network
		config_foreach wireguard_restart interface
	fi

}

boot() {
	BOOT=1
	start
}

service_triggers() {
	procd_add_reload_trigger "openmptcprouter" "network"
}